//
//  AVDFlutterWrapper.m
//  avd_sdk_plugin
//
//  Created by 3tee on 2023/6/8.
//

#import "AVDFlutterWrapper.h"
#import "AVDFlutterMethodKey.h"
#import <avd_sdk/avd_sdk.h>

@interface AVDFlutterWrapper ()<AVDEngineDelegate,AVDRoomJoinDelegate,AVDRoomDelegate,AVDVideoDelegate,AVDAudioDelegate,AVDScreenDelegate,AVDChatDelegate,AVDUserManagerDelegate>

@property (nonatomic, strong) FlutterMethodChannel *channel;
@property (nonatomic, strong) RTCVideoViewFactory *factory;

@property (nonatomic, strong) NSString *sdkVersion;
@property (nonatomic, strong) NSString *roomId;
@property (nonatomic, strong)AVDRoom *mRoom;/**房间模块*/
@property (nonatomic, strong)AVDVideo *mVideo;/**视频模块*/
@property (nonatomic, strong)AVDAudio *mAudio;/**音频模块*/
@property (nonatomic, strong)AVDScreen *mScreen;/**屏幕共享模块*/
@property (nonatomic, strong)AVDChat *mChat;/**聊天模块*/
@property (nonatomic, strong)AVDUserManager *mUserManager;/**参会者模块*/

@end

@implementation AVDFlutterWrapper

-(void)dealloc{
    NSLog(@"AVDFlutterWrapper dealloc♻️");
}

static AVDFlutterWrapper *wrapper = nil;

+ (instancetype)sharedWrapper {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        wrapper = [[self alloc] init];
    });
    return wrapper;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        
    }
    return self;
}

- (void)setFlutterChannel:(FlutterMethodChannel *)channel {
    self.channel = channel;
}

- (void)setVideoViewFactory:(RTCVideoViewFactory *_Nullable)factory{
    self.factory = factory;
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
    if([AVDMethod_init isEqualToString:call.method]){
        NSLog(@"init args = %@",(NSDictionary *)call.arguments);
        [self initEngine:call.arguments];
        result(nil);
    }
    else if ([AVDMethod_getVersion isEqualToString:call.method]){
        NSString *version = [AVDEngine getVersion];
        result(version);
    }
    else if ([AVDMethod_setLogParams isEqualToString:call.method]){
        NSDictionary *dic = (NSDictionary *)call.arguments;
        NSLog(@"setlogparms = %@",dic);
        [[AVDEngine instance] setLogParams:dic[@"parms"] file:dic[@"path"]];
        result(nil);
    }
    
    else if ([AVDMethod_joinRoom isEqualToString:call.method]){
        NSLog(@"joinRoom args = %@",(NSDictionary *)call.arguments);
        [self joinRoom:call.arguments];
        result(nil);
    }
    else if ([AVDMethod_publishCamera isEqualToString:call.method]){
        [self publishCamera];
        result(nil);
    }
    else if ([AVDMethod_unpublishCamera isEqualToString:call.method]){
        [self unpublishCamera];
        result(nil);
    }
    else if ([AVDMethod_attachRenderWithDeviceId isEqualToString:call.method]){
        AVDResult code = [self attachRenderWithDeviceId:call.arguments];
        result(@(code));
    }
    else if ([AVDMethod_detachRenderWithDeviceId isEqualToString:call.method]){
        AVDResult code = [self detachRenderWithDeviceId:call.arguments];
        result(@(code));
    }
    else if ([AVDMethod_subscribe isEqualToString:call.method]){
        AVDResult code = [self subscribe:call.arguments];
        result(@(code));
    }
    else if ([AVDMethod_unsubscribe isEqualToString:call.method]){
        AVDResult code = [self unsubscribe:call.arguments];
        result(@(code));
    }
    else if ([AVDMethod_switchToLocalCamera isEqualToString:call.method]){
        [self switchCamera];
        result(nil);
    }
    else if ([AVDMethod_openMicrophone isEqualToString:call.method]){
        AVDResult code = [self.mAudio openMicrophone];
        result(@(code));
    }
    else if ([AVDMethod_closeMicrophone isEqualToString:call.method]){
        AVDResult code = [self.mAudio closeMicrophone];
        result(@(code));
    }
    else if ([AVDMethod_leaveRoom isEqualToString:call.method]){
        [self closeRoom:NO];
        result(nil);
    }
    else if ([AVDMethod_closeRoom isEqualToString:call.method]){
        [self closeRoom:YES];
        result(nil);
    }
    else if ([AVDMethod_getPublishedCameras isEqualToString:call.method]){
        [self getPublishedCameraList:call.arguments result:result];
    }
    else if ([AVDMethod_setSpeakerMode isEqualToString:call.method]){
        [self setSpeakerMode:call.arguments];
        result(nil);
    }
    else if ([AVDMethod_sendPublicMessage isEqualToString:call.method]){
        [self sendPublicMessage:call.arguments];
        result(nil);
    }
    else if ([AVDMethod_sendPrivateMessage isEqualToString:call.method]){
        [self sendPrivateMessage:call.arguments];
        result(nil);
    }
    else if ([AVDMethod_publishScreen isEqualToString:call.method]){
        [self.mScreen publishScreen:screen_resolution_720p fps:15];
        result(nil);
    }
    else if ([AVDMethod_unpublishScreen isEqualToString:call.method]){
        [self.mScreen unpublishScreen];
        result(nil);
    }
    else if ([AVDMethod_scheduleRoom isEqualToString:call.method]){
        [self scheduleRoom:call.arguments result:result];
    }
    
}

#pragma mark - selector
- (void)initEngine:(id)arg{
    if([arg isKindOfClass:[NSDictionary class]]){
        NSString *appKey = arg[@"appKey"];
        NSString *secretKey = arg[@"secretKey"];
        NSString *url = arg[@"url"];
        [[AVDEngine instance]initWithServerUrl:url accessKey:appKey secretKey:secretKey  delegate:self];
    }
}

- (void)joinRoom:(id)arg{
    if([arg isKindOfClass:[NSDictionary class]]){
        NSString *roomId = arg[@"roomId"];
        NSString *userData = arg[@"userData"];
        NSString *userId = arg[@"userId"];
        NSString *userName = arg[@"userName"];
        AVDRoom *room = [AVDRoom obtain:roomId];
        AVDUser *user = [[AVDUser alloc]initWithUserId:userId userName:userName userData:userData];
        [room joinWithUser:user delegate:self];
        self.roomId = roomId;
    }
}

- (void)configMoudles{
    self.mRoom = [AVDRoom obtain:self.roomId];
    self.mRoom.delegate = self;
    self.mAudio = [AVDAudio getAudio:self.mRoom];
    self.mAudio.delegate = self;
    self.mVideo = [AVDVideo getVideo:self.mRoom];
    self.mVideo.delegate = self;
    self.mScreen = [AVDScreen getScreen:self.mRoom];
    self.mScreen.delegate = self;
    self.mChat = [AVDChat getChat:self.mRoom];
    self.mChat.delegate = self;
    self.mUserManager = [AVDUserManager getUserManager:self.mRoom];
    self.mUserManager.delegate = self;
}

- (void)publishCamera{
    [self.mVideo publishLocalCamera];
}

- (void)unpublishCamera{
    [self.mVideo unpublishLocalCamera];
}

- (AVDResult)attachRenderWithDeviceId:(id)arg{
    if([arg isKindOfClass:[NSDictionary class]]){
        NSString *did = arg[@"deviceid"];
        NSString *tagId = arg[@"tagId"];
        RTCVideoView *temp = nil;
        for (RTCVideoView *render in self.factory.rendermArr) {
            if ([render.tagId isEqualToString:tagId]) {
                temp = render;
            }
        }
        if(temp){
            return [self.mVideo attachRenderWithDeviceId:did render:temp];
        }else{
            NSLog(@"RTCVideoView not found");
        }
        
    }
    return -1;
}



- (AVDResult)detachRenderWithDeviceId:(id)arg{
    if([arg isKindOfClass:[NSDictionary class]]){
        NSString *did = arg[@"deviceid"];
        NSString *tagId = arg[@"tagId"];
        RTCVideoView *temp = nil;
        for (RTCVideoView *render in self.factory.rendermArr) {
            if ([render.tagId isEqualToString:tagId]) {
                temp = render;
            }
        }
        if(temp){
            return [self.mVideo detachRenderWithRender:temp];
        }else{
            NSLog(@"RTCVideoView not found");
        }
        
    }
    return -1;
}

- (AVDResult)subscribe:(id)arg{
    return [self.mVideo subscribe:arg[@"deviceid"]];
}

- (AVDResult)unsubscribe:(id)arg{
    return [self.mVideo unsubscribe:arg[@"deviceid"]];
}

- (void)switchCamera{
    [self.mVideo switchToLocalCamera];
}

- (void)closeRoom:(BOOL)isClose{
    isClose?[self.mRoom close] : [self.mRoom leave:0];
    [self.mRoom destory];
    [self.factory.rendermArr removeAllObjects];
    self.mRoom = nil;
    self.mAudio = nil;
    self.mVideo = nil;
    self.mScreen = nil;
    self.mChat = nil;
    self.mUserManager = nil;
}

- (void)getPublishedCameraList:(id)arg result:(FlutterResult)result{
    //NSLog(@"getPublishedCameraList count = %d",self.mVideo.publishedCameras.count);
    if (self.mVideo.publishedCameras.count > 0) {
              NSMutableArray *arr = [NSMutableArray new];
              for(AVDCamera *camera in self.mVideo.publishedCameras) {
                  [arr addObject:camera.id];
              }
              result(@{@"publishedCameraList": [arr copy]});
          }else {
              result(@{@"publishedCameraList": @[]});
          }
}

- (void)setSpeakerMode:(id)arg{
    NSLog(@"setSpeakerMode arg = %@",arg);
    if([arg isKindOfClass:[NSDictionary class]]){
        NSInteger mode = arg[@"modelValue"];
        [self.mAudio setSpeakerMode:mode == 0 ?SM_Handfree:SM_Receiver];
    }
}

- (void)sendPublicMessage:(id)arg{
    if([arg isKindOfClass:[NSDictionary class]]){
        NSString * msg = arg[@"msg"];
        [self.mChat sendPublicMessage:msg];
    }
}

- (void)sendPrivateMessage:(id)arg{
    if([arg isKindOfClass:[NSDictionary class]]){
        NSString * msg = arg[@"msg"];
        NSString * uid = arg[@"uid"];
        [self.mChat sendPrivateMessage:msg toUser:uid];
    }
}

- (void)scheduleRoom:(id)arg result:(FlutterResult)result{
    if([arg isKindOfClass:[NSDictionary class]]){
        NSString * roomId = arg[@"roomId"];
        NSString * roomName = arg[@"roomName"];
        NSString * roomTopic = arg[@"roomTopic"];
        NSString * owerId = arg[@"owerId"];
        AVDRoomInfo * info = [[AVDRoomInfo alloc]initWithRoomId:roomId roomName:roomName appRoomId:roomId ownerId:owerId maxAttendee:100 maxAudio:100 maxVideo:100 roomMode:1 voiceActivated:YES];
        [info setRoomModeFlag:mcu];
        [[AVDEngine instance] scheduleRoom:info];
    }
}


#pragma mark - AVDEngineDelegate
-(void)onInitResult:(AVDResult)result{
    [self.channel invokeMethod:AVDMethodCallBack_onInitResult arguments:@(result)];
}

- (void)onScheduleRoomResult:(AVDResult)result roomId:(AVDRoomId)roomId{
    NSDictionary *dic = @{@"result": @(result),
                          @"roomId": roomId};
    [self.channel invokeMethod:AVDMethodCallBack_onScheduleRoomResult arguments:dic];
}

#pragma mark - AVDRoomDelegate
-(void)onJoinResult:(AVDResult)result{
    [self.channel invokeMethod:AVDMethodCallBack_onJoinResult arguments:@(result)];
    if(result == AVD_Success){
        [self configMoudles];
    }
}

#pragma mark - AVDVideoDelegate
- (void)onPublishLocalResult:(AVDResult)result deviceId:(AVDDeviceId)fromId{
    NSLog(@"renders = %@",self.factory.rendermArr);
    [self.channel invokeMethod:AVDMethodCallBack_onPublishLocalResult arguments:fromId];
}

- (void)onUnpublishLocalResult:(AVDResult)result deviceId:(AVDDeviceId)fromId{
    [self.channel invokeMethod:AVDMethodCallBack_onUnpublishLocalResult arguments:fromId];
}

- (void)onPublishCameraNotify:(AVDCamera *)camera{
    [self.channel invokeMethod:AVDMethodCallBack_onPublishCameraNotify arguments:camera.id];
    
}

- (void)onUnpublishCameraNotify:(AVDCamera *)camera{
    [self.channel invokeMethod:AVDMethodCallBack_onUnpublishCameraNotify arguments:camera.id];
    
}
#pragma mark - AVDAudioDelegate

#pragma mark - AVDUserDelegate
- (void)onUserJoinNotify:(AVDUser *)user{
    NSDictionary *dic = @{@"userId": user.userId,
                          @"userName": user.userName,
                          @"userData":user.userData,
                          @"userAgent":user.userAgent};
    [self.channel invokeMethod:AVDMethodCallBack_onUserJoinNotify arguments:dic];
}

- (void)onUserLeaveNotify:(AVDResult)reason leaveUser:(AVDUser *)user {
    NSDictionary *dic = @{@"userId": user.userId,
                          @"userName": user.userName,
                          @"userData":user.userData,
                          @"userAgent":user.userAgent,
                          @"reason":@(reason)};
    [self.channel invokeMethod:AVDMethodCallBack_onUserLeaveNotify arguments:dic];
}

#pragma mark - AVDChatDelegate
- (void)onPublicMessage:(AVDMessage *)message{
    NSDictionary *dic = @{@"fromId": message.fromId,
                          @"message": message.message,
                          @"fromName":message.fromName};
    [self.channel invokeMethod:AVDMethodCallBack_onPublicMessage arguments:dic];
}

- (void)onPrivateMessage:(AVDMessage *)message{
    NSDictionary *dic = @{@"fromId": message.fromId,
                          @"message": message.message,
                          @"fromName":message.fromName};
    [self.channel invokeMethod:AVDMethodCallBack_onPrivateMessage arguments:dic];
}

#pragma mark - AVDWScreenDelegate
- (void)onPublishScreenNotify:(AVDVideoDevice *)screen{
    [self.channel invokeMethod:AVDMethodCallBack_onPublishScreenNotify arguments:screen.id];
}

- (void)onUnpublishScreenNotify:(AVDVideoDevice *)screen{
    [self.channel invokeMethod:AVDMethodCallBack_onUnpublishScreenNotify arguments:screen.id];
}

- (void) onSubscribeResult:(AVDResult)result deviceId:(AVDDeviceId)fromId{
    NSDictionary *dic = @{@"deviceid": fromId,
                          @"result": @(result)};
    [self.channel invokeMethod:AVDMethodCallBack_onSubscribeScreenResult arguments:dic];
}

- (void) onUnsubscribeResult:(AVDResult)result deviceId:(AVDDeviceId)fromId{
    NSDictionary *dic = @{@"deviceid": fromId,
                          @"result": @(result)};
    [self.channel invokeMethod:AVDMethodCallBack_onUnsubscribeScreenResultt arguments:dic];;

}

#pragma mark - AVDWhiteboardDelegate


@end
